﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace Spore.Utils
{
    public class NetClient : ChannelBase<Dto>
    {
        private int readProgress;
        private DataReadStatus readStatus;
        private const int headSize = 9;
        byte[] head = new byte[headSize];
        byte[] dataBady = new byte[8 * 1024];
        int willReadDataLength;
        int willReadDataID;
        bool dataIsCompress;
        byte[] writingData;
        int writeProgress;
        
        private DTOTypeConverter converter;

        public NetClient(Socket socket, DTOTypeConverter converter):base(socket)
        {
            this.converter = converter;
        }

        protected override void OnReadData()
        {
            this.readProgress += this.readAsy.BytesTransferred;
            if (this.readProgress < this.readAsy.Count)
            {
                this.readAsy.SetBuffer(readProgress, this.readAsy.Count - readProgress);
            }
            else
            {
                if (this.readStatus == DataReadStatus.HeadReading)
                    ReadHead();
                else if (this.readStatus == DataReadStatus.BodyReading)
                    ReadBady();
                else
                {
#if DEBUG
                    System.Diagnostics.Debug.Assert(false, "数据通道接收状态不对");
#endif
                }
            }
            
            if (!this.socket.ReceiveAsync(readAsy))
            {
                
                //Console.WriteLine("同步接收…………");
                this.OnReadComplete();
            }

        }

        private void ReadBady()
        {
            this.readStatus = DataReadStatus.BodyReaded;
            object obj =SerializationHelper.GetValue(readAsy.Buffer, 0,willReadDataLength);
            this.BufferReader.AddElement(new Dto(this.willReadDataID, obj,this));
            this.OnReadElement();
            this.readProgress = 0;
            this.readStatus = DataReadStatus.HeadReading;
            this.readAsy.SetBuffer(this.head, 0, headSize);
        }

        private void ReadHead()
        {
            this.readStatus = DataReadStatus.HeadReaded;
            this.willReadDataLength = BitConverter.ToInt32(head, 0);
            this.dataIsCompress = head[4] == 1;
            this.willReadDataID = BitConverter.ToInt32(head, 5);
            readStatus = DataReadStatus.BodyReading;
            this.readProgress = 0;
            if (willReadDataLength > this.dataBady.Length)
            {
                byte[] temp = new byte[willReadDataLength];
                this.readAsy.SetBuffer(temp, 0, willReadDataLength);
            }
            else
            {
                this.readAsy.SetBuffer(dataBady, 0, willReadDataLength);
            }
        }

        protected override void OnWriteData()
        {
            if (this.writingData != null)
            {
                this.writeProgress += this.writeAsy.BytesTransferred;
                if (this.writeProgress < this.writeAsy.Count)
                {
                    this.writeAsy.SetBuffer(this.writeProgress, this.writeAsy.Count - this.writeProgress);
                    if (!this.socket.SendAsync(writeAsy))
                    {
                        this.OnWriteComplete();
                    }
                }
                else
                {
                    InnerWriteData();
                }
            }
            else
            {
                InnerWriteData();
            }
        }

        protected override void OnOpen()
        {
            this.readAsy.SetBuffer(this.head, 0, headSize);
            if (!this.socket.ReceiveAsync(this.readAsy))
            {
                this.socket.ReceiveAsync(readAsy);
            }
        }

        private void InnerWriteData()
        {
            if (bufferWriter.HasElement)
            {
                this.writing = true;
                writeProgress = 0;
                Dto dto = this.bufferWriter.GetAndRemoveElement();
                byte[] temp = SerializationHelper.GetBytes(dto.RealData);
                this.writingData = new byte[temp.Length + headSize];
                byte[] length = BitConverter.GetBytes(temp.Length);
                Array.Copy(BitConverter.GetBytes(temp.Length), 0, writingData, 0, 4);
                writingData[4] = 0;
                Array.Copy(BitConverter.GetBytes(dto.DataID), 0, writingData, 5, 4);
                Array.Copy(temp, 0, writingData, headSize, temp.Length);
                this.writeAsy.SetBuffer(this.writingData, 0, this.writingData.Length);
                if (!this.socket.SendAsync(writeAsy))
                {
                    this.OnWriteComplete();
                }
            }
            else
            {
                this.writingData = null;
                this.writing = false;
            }
        }
    }

    public enum DataReadStatus
    {
        HeadReading,
        HeadReaded,
        BodyReading,
        BodyReaded
    }
}
